﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.ServiceModel;
using dbfile = DBFile.Wcf;
using DBFile.WcfFileProvider.Interfaces;
using System.ServiceModel.Description;
using System.Xml;

namespace DBFile.AzureWorker.FileService
{
    public class WorkerRole : RoleEntryPoint
    {
        private ServiceHost serviceHost;

        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;
            
            DiagnosticMonitorConfiguration config = DiagnosticMonitor.GetDefaultInitialConfiguration();
            
            config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            config.DiagnosticInfrastructureLogs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
            config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            
            DiagnosticMonitor.Start("DiagnosticsConnectionString", config);
            DiagnosticMonitor.AllowInsecureRemoteConnections = true;

            RoleEnvironment.Changing += RoleEnvironmentChanging;

            return base.OnStart();
        }


        public override void Run()
        {
            Trace.WriteLine("DBFile.AzureWorker.FileService entry point called", "Information");


            this.StartFileService(3);

            while (true)
            {
                Thread.Sleep(30000);
                Trace.TraceInformation("Working...");
            }
        }

        private void StartFileService(int retries)
        {
            if (retries == 0)
            {
                RoleEnvironment.RequestRecycle();
                return;
            }
            Trace.TraceInformation("Starting DBFile service host...");

            this.serviceHost = new ServiceHost(typeof(dbfile.FileService));

            this.serviceHost.Faulted += (sender, e) =>
            {
                Trace.TraceError("Host fault occured. Aborting and restarting the host. Retry count: {0}", retries);
                this.serviceHost.Abort();
                this.StartFileService(--retries);
            };

            // use NetTcpBinding with no security
            NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
            
            // define an external endpoint for client traffic
            RoleInstanceEndpoint externalEndPoint =
                RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["DBFileService"];

            binding.TransferMode = TransferMode.Streamed;
            binding.MaxBufferSize = 2147483647;
            binding.MaxBufferPoolSize = 2147483647;
            binding.MaxReceivedMessageSize = 2147483647;

            binding.ReaderQuotas.MaxDepth = 2147483647;
            binding.ReaderQuotas.MaxStringContentLength = 2147483647;
            binding.ReaderQuotas.MaxArrayLength = 2147483647;
            binding.ReaderQuotas.MaxBytesPerRead = 2147483647;
            binding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
                        
            this.serviceHost.AddServiceEndpoint(
                typeof(IFileProvider),
                binding,
                String.Format("net.tcp://{0}/dbfileservice", externalEndPoint.IPEndpoint));

            ServiceMetadataBehavior metadataBehavior = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (metadataBehavior == null)
            {
                metadataBehavior = new ServiceMetadataBehavior();
                serviceHost.Description.Behaviors.Add(metadataBehavior);
            }

            RoleInstanceEndpoint externalMexEndPoint =
               RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MEX"];

            serviceHost.AddServiceEndpoint(typeof(IMetadataExchange),
                binding,
                String.Format("net.tcp://{0}/mex", externalMexEndPoint.IPEndpoint));

            Trace.TraceInformation("DBFileService URI: " + String.Format("net.tcp://{0}/DBFileService", externalEndPoint.IPEndpoint));
            Trace.TraceInformation("MEX URI: " + String.Format("net.tcp://{0}/MEX", externalMexEndPoint.IPEndpoint));
            
            try
            {
                this.serviceHost.Open();
                Trace.TraceInformation("DBFile service host started successfully.");
            }
            catch (TimeoutException timeoutException)
            {
                Trace.TraceError("The service operation timed out. {0}", timeoutException.Message);
            }
            catch (CommunicationException communicationException)
            {
                Trace.TraceError("Could not start chat service host. {0}", communicationException.Message);
            }

        }

        
        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
    }
}
